package com.cctc.aop;

import com.cctc.aop.audit.annotation.Auditable;
import com.cctc.entity.PurchaseEntity;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DataAccessException;

/**
 * @Name CommonAdvice
 * @Description: 代理行动
 * @Author: lichao
 * @Email: li2chao@126.com
 * @Date: 2024-01-18 19:43:35
 **/
@Aspect
public class CommonAdvice {

    /**
     * 在 [目标方法执行前] 回调方法
     * @param joinPoint 织入点
     * @param purchase 目标方法的参数
     * @author lichao
     * @email li2chao@126.com
     * @date 2024/01/18 20:21:19
     */
    @Order(1)
    @Before("com.cctc.aop.CommonPointCuts.inServiceLayerAllMethod(purchase)")
    public void checkBeforeCall(JoinPoint joinPoint, PurchaseEntity purchase) {
        // 获取目标方法的参数
        joinPoint.getArgs();
        // 获取代理对象
        joinPoint.getThis();
        // 获取目标对象
        joinPoint.getTarget();
        // 获取目标方法的 {返回值、方法名等} 描述
        joinPoint.getSignature();
        // ... ...
    }

    /**
     * 在 [带注解的目标方法执行前] 回调方法
     * @param joinPoint 织入点
     * @param auditable 目标注解
     * @author lichao
     * @email li2chao@126.com
     * @date 2024/01/18 21:06:22
     */
    @Order(0)
    @Before(
            value = "com.cctc.aop.CommonPointCuts.inAuditableServiceMethod() && @annotation(auditable)",
            argNames = "joinPoint,auditable"
    )
    public void auditableAnnotationCheckBeforeCall(JoinPoint joinPoint, Auditable auditable) {
        boolean flag = auditable.value();
        // ... ...
    }

    /**
     * 在 [目标方法正常返回后] 回调方法，处理返回结果
     * @param joinPoint 织入点
     * @param retVal 返回值
     * @author lichao
     * @email li2chao@126.com
     * @date 2024/01/18 20:25:28
     */
    @AfterReturning(
            pointcut = "com.cctc.aop.CommonPointCuts.inDaoLayerAllMethod()",
            returning = "retVal"
    )
    public void processReturnResult(JoinPoint joinPoint, Object retVal) {
        // ... ...
    }

    /**
     * 在 [目标方法执行过程中遇到异常时] 回调方法，处理异常信息
     * @param joinPoint 织入点
     * @param ex 异常信息
     * @author lichao
     * @email li2chao@126.com
     * @date 2024/01/18 20:30:07
     */
    @AfterThrowing(
            pointcut = "com.cctc.aop.CommonPointCuts.inDaoLayerAllMethod()",
            throwing = "ex"
    )
    public void processException(JoinPoint joinPoint, DataAccessException ex) {
        // ... ...
    }

    /**
     * 在 [目标方法执行结束后] 回调方法，通常被用于释放资源和类似的目的。
     * @param joinPoint 织入点
     * @author lichao
     * @email li2chao@126.com
     * @date 2024/01/18 20:31:34
     */
    @After("com.cctc.aop.CommonPointCuts.inDaoLayerAllMethod()")
    public void doFinally(JoinPoint joinPoint) {
        // ... ...
    }

    /**
     * 在 [目标方法执行前、中、后等全栈范围] 回调方法。
     * "围绕" 一个匹配的方法的执行而运行，且允许多次调用 proceed() 方法。
     * 它有机会在方法运行之前和之后进行工作，并决定何时、如何、甚至是否真正运行该方法。
     * 如果你需要以线程安全的方式分享方法执行前后的状态，例如启动和停止一个定时器，那么 Around 行动将经常被使用。
     * @param joinPoint [ProceedingJoinPoint] 类型的织入点
     * @return java.lang.Object 目标方法的返回值
     * @author lichao
     * @email li2chao@126.com
     * @date 2024/01/18 20:37:48
     */
    @Around("com.cctc.aop.CommonPointCuts.inServiceLayerAllMethod(purchase)")
    public Object fullyProcess(ProceedingJoinPoint joinPoint, PurchaseEntity purchase) throws Throwable {
        // [目标方法执行前] 的操作
        // ... ...
        Object retVal = joinPoint.proceed(new Object[] {purchase}); // 执行目标方法
        // [目标方法执行结束后] 的操作
        // ... ..
        return retVal;
    }

}

